﻿using System;
using System.Linq;
using System.Web.Mvc;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common.Models;
using Orchard.Core.Contents;
using Orchard.Core.Contents.Controllers;
using Orchard.Core.Contents.Settings;
using Orchard.Core.Contents.ViewModels;
using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Mvc;
using Orchard.Settings;
using Orchard.Themes;
using Orchard.UI.Navigation;
using Orchard.UI.Notify;

namespace ContentCreator.Controllers
{
    public class AdminController : Controller, IUpdateModel
    {
        private readonly ISiteService _siteService;
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly IContentManager _contentManager;
        private readonly ITransactionManager _transactionManager;

        public AdminController(
            IOrchardServices orchardServices,
            ISiteService siteService,
            IContentDefinitionManager contentDefinitionManager,
            IContentManager contentManager,
            ITransactionManager transactionManager)
        {

            _siteService = siteService;
            _contentDefinitionManager = contentDefinitionManager;
            Services = orchardServices;
            T = NullLocalizer.Instance;
            _contentManager = contentManager;
            _transactionManager = transactionManager;
        }

        public IOrchardServices Services { get; set; }
        public Localizer T { get; set; }

        [Themed(false)]
        public ActionResult Create(string contentType)
        {
            var contentItem = _contentManager.New(contentType);

            if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Cannot create content")))
            {
                return new HttpUnauthorizedResult();
            }


            var model = _contentManager.BuildEditor(contentItem);

            dynamic tab = Services.New.ContentTab();
            tab.Content = model;

            return new ShapeResult(this, Services.New.ContentCreator().Tab(tab));
        }

        [Themed(false)]
        [HttpPost, ActionName("Create")]
        [FormValueRequired("submit.Save")]
        public ActionResult CreatePOST(ListContentsViewModel model, string callback, string contentType)
        {
            return CreatePOST(model, callback, contentType, contentItem =>
            {
                if (!contentItem.Has<IPublishingControlAspect>() && !contentItem.TypeDefinition.Settings.GetModel<ContentTypeSettings>().Draftable)
                {
                    _contentManager.Publish(contentItem);
                }
            });
        }

        [Themed(false)]
        [HttpPost, ActionName("Create")]
        [FormValueRequired("submit.Publish")]
        public ActionResult CreateAndPublishPOST(ListContentsViewModel model, string callback, string contentType)
        {
            // pass a dummy content to the authorization check to check for "own" variations
            var dummyContent = _contentManager.New(contentType);

            if (!Services.Authorizer.Authorize(Permissions.PublishContent, dummyContent, T("Couldn't create content")))
            {
                return new HttpUnauthorizedResult();
            }

            return CreatePOST(model, callback, contentType, contentItem => _contentManager.Publish(contentItem));
        }


        private ActionResult CreatePOST(ListContentsViewModel model, string callback, string contentType, Action<ContentItem> conditionallyPublish)
        {
            var contentItem = _contentManager.New(contentType);

            if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't create content")))
            {
                return new HttpUnauthorizedResult();
            }

            _contentManager.Create(contentItem, VersionOptions.Draft);

            var m = _contentManager.UpdateEditor(contentItem, this);
            if (!ModelState.IsValid)
            {
                _transactionManager.Cancel();
                dynamic t = Services.New.ContentTab();
                t.Content = m;

                return new ShapeResult(this, Services.New.ContentCreator().Tab(t));
            }

            conditionallyPublish(contentItem);

            Services.Notifier.Information(string.IsNullOrWhiteSpace(contentItem.TypeDefinition.DisplayName)
                ? T("Your content has been created.")
                : T("Your {0} has been created.", contentItem.TypeDefinition.DisplayName));

            dynamic tab = Services.New.RedirectTab();
            tab.ContentId = contentItem.Id;
            tab.DisplayText = contentType;
            tab.Callblack = callback;

            return new ShapeResult(this, Services.New.ContentCreator().Tab(tab));
        }

        bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties)
        {
            return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
        }

        void IUpdateModel.AddModelError(string key, LocalizedString errorMessage)
        {
            ModelState.AddModelError(key, errorMessage.ToString());
        }

        [Themed(false)]
        public ActionResult Pick(ListContentsViewModel model, PagerParameters pagerParameters, string contentType)
        {
            var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);

            var query = Services.ContentManager.Query(VersionOptions.Latest, contentType);

            if (!string.IsNullOrEmpty(model.Options.SelectedFilter))
            {
                var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.Options.SelectedFilter);
                if (contentTypeDefinition == null)
                    return HttpNotFound();

                model.TypeDisplayName = !string.IsNullOrWhiteSpace(contentTypeDefinition.DisplayName)
                                            ? contentTypeDefinition.DisplayName
                                            : contentTypeDefinition.Name;
                query = query.ForType(model.Options.SelectedFilter);

            }

            switch (model.Options.OrderBy)
            {
                case ContentsOrder.Modified:
                    query = query.OrderByDescending<CommonPartRecord>(cr => cr.ModifiedUtc);
                    break;
                case ContentsOrder.Published:
                    query = query.OrderByDescending<CommonPartRecord>(cr => cr.PublishedUtc);
                    break;
                case ContentsOrder.Created:
                    query = query.OrderByDescending<CommonPartRecord>(cr => cr.CreatedUtc);
                    break;
            }

            var pagerShape = Services.New.Pager(pager).TotalItemCount(query.Count());
            var pageOfContentItems = query.Slice(pager.GetStartIndex(), pager.PageSize).ToList();

            var list = Services.New.List();
            list.AddRange(pageOfContentItems.Select(ci => Services.ContentManager.BuildDisplay(ci, "SummaryAdmin")));

            foreach (IShape item in list.Items)
            {
                item.Metadata.Type = "ContentCreator";
            }

            dynamic tab = Services.New.PickContentTab()
                .ContentItems(list)
                .Pager(pagerShape)
                .Options(model.Options)
                .TypeDisplayName(model.TypeDisplayName ?? "");

            // retain the parameter in the pager links
            RouteData.Values["Options.OrderBy"] = model.Options.OrderBy.ToString();

            return new ShapeResult(this, Services.New.ContentCreator().Tab(tab));
        }
    }
}